/**
 * 命令基类
 * 提供基础的命令打包和解析功能
 */
class BaseCommand {
  // 帧头定义
  static FRAME_HEAD = 0x55AA;

  /**
   * 打包命令帧
   * @param {number} cmd - 命令类型
   * @param {Uint8Array} data - 命令数据
   * @returns {Uint8Array} 完整的命令帧
   */
  static packFrame(cmd, data = null) {
    console.log('[CMD] 开始打包命令:', { cmd: `0x${cmd.toString(16)}`, data });
    
    const dataLength = data ? data.length : 0;
    const frameLength = 7 + dataLength; // 帧头(2) + 长度(2) + 命令(1) + 数据(n) + CRC(2)
    const frame = new Uint8Array(frameLength);
    
    // 帧头
    frame[0] = (this.FRAME_HEAD >> 8) & 0xFF;
    frame[1] = this.FRAME_HEAD & 0xFF;
    
    // 数据长度
    frame[2] = (dataLength >> 8) & 0xFF;
    frame[3] = dataLength & 0xFF;
    
    // 命令类型
    frame[4] = cmd;
    
    // 数据部分
    if (data) {
      frame.set(data, 5);
    }
    
    // 计算 CRC
    const crc = this.calculateCRC16(frame.slice(0, frameLength - 2));
    frame[frameLength - 2] = crc & 0xFF;
    frame[frameLength - 1] = (crc >> 8) & 0xFF;

    console.log('[CMD] 命令打包完成:', Array.from(frame).map(b => `0x${b.toString(16).padStart(2, '0')}`).join(' '));
    return frame;
  }

  /**
   * 解析基础帧结构
   * @param {Uint8Array} frame - 接收到的数据帧
   * @returns {Object|null} 解析结果: {cmd, data} 或 null
   */
  static parseBaseFrame(frame) {
    console.log('[CMD] 开始解析数据帧:', Array.from(frame).map(b => `0x${b.toString(16).padStart(2, '0')}`).join(' '));

    // 检查最小长度
    if (frame.length < 7) {
      console.warn('[CMD] 数据帧长度不足');
      return null;
    }

    // 检查帧头
    const head = (frame[0] << 8) | frame[1];
    if (head !== this.FRAME_HEAD) {
      console.warn('[CMD] 帧头不匹配:', `0x${head.toString(16)}`, `预期: 0x${this.FRAME_HEAD.toString(16)}`);
      return null;
    }

    // 获取数据长度
    const length = (frame[2] << 8) | frame[3];
    if (frame.length !== length + 7) {
      console.warn('[CMD] 数据长度不匹配:', frame.length, '预期:', length + 7);
      return null;
    }

    // 检查 CRC
    const crcReceived = (frame[frame.length - 1] << 8) | frame[frame.length - 2];
    const crcCalculated = this.calculateCRC16(frame.slice(0, frame.length - 2));
    if (crcReceived !== crcCalculated) {
      console.warn('[CMD] CRC校验失败:', `0x${crcReceived.toString(16)}`, `计算值: 0x${crcCalculated.toString(16)}`);
      return null;
    }

    const cmd = frame[4];
    const data = frame.slice(5, 5 + length);
    console.log('[CMD] 基础帧解析成功:', { cmd: `0x${cmd.toString(16)}`, dataLength: data.length });

    return { cmd, data };
  }

  /**
   * 计算 CRC16
   * @private
   */
  static calculateCRC16(data) {
    let crc = 0xFFFF;
    for (let i = 0; i < data.length; i++) {
      crc ^= data[i];
      for (let j = 0; j < 8; j++) {
        if (crc & 1) {
          crc = (crc >> 1) ^ 0xA001;
        } else {
          crc >>= 1;
        }
      }
    }
    return crc;
  }
}

export default BaseCommand; 